﻿using System;
using System.Collections.Generic;
using System.Windows.Input;

namespace Chisel.Core
{
    /// <summary>
    /// Keeps track of the actors in a canvas.
    /// </summary>
    public class ActorCollection<T> where T : Actor
    {


        #region All

        private List<T> _all = new List<T>();
        /// <summary>
        /// All of the actors in the collection.
        /// </summary>
        public IList<T> All
        {
            get { return _all; }
        }

        /// <summary>
        /// Adds an actor to the collection.
        /// </summary>
        public void Add(T actor)
        {
            _all.Add(actor);
        }

        /// <summary>
        /// Removes an actor from the collection.
        /// </summary>
        public void Remove(T actor)
        {
            _all.Remove(actor);
        }

		/// <summary>
		/// Gets the actor after the given one.
		/// </summary>
		/// <remarks>Wraps to the front if it's the last one.</remarks>
		public T GetNext(T actor)
		{
			var index = _all.IndexOf(actor);
			if (index < _all.Count - 1)
				return _all[index + 1];
			else
				return _all[0];
		}

        #endregion


        #region Selected

        private List<T> _selected = new List<T>();
        /// <summary>
        /// The selected actors in the collection.
        /// </summary>
        public IList<T> Selected
        {
            get { return _selected; }
        }

        private List<ISelectionListener> _selectionListeners = new List<ISelectionListener>();

        /// <summary>
        /// Registers a selection listener.
        /// </summary>
        public void RegisterSelectionListener(ISelectionListener listener)
        {
            _selectionListeners.Add(listener);
        }

        /// <summary>
        /// Selects an actor and propagates the action to all listeners.
        /// </summary>
        public void Select(T actor)
        {
            Select(actor, null);
        }
        
        /// <summary>
        /// Selects an actor and propagates the action to all listeners excpet sender.
        /// </summary>
        public void Select(T actor, ISelectionListener sender)
        {
            actor.OnSelect();
            _selected.Add(actor);
            foreach (var listener in _selectionListeners)
            {
                if (sender == null || sender != listener)
                    listener.OnSelect(actor);
            }
        }

        /// <summary>
        /// Deselects an actor and propagates the action to all listeners.
        /// </summary>
        public void Deselect(T actor)
        {
            Deselect(actor, null);
        }

        /// <summary>
        /// Deselects an actor and propagates the action to all listeners excpet sender.
        /// </summary>
        public void Deselect(T actor, ISelectionListener sender)
        {
            actor.OnDeselect();
            _selected.Remove(actor);
            foreach (var listener in _selectionListeners)
            {
                if (sender == null || sender != listener)
                    listener.OnDeselect(actor);
            }
        }

        /// <summary>
        /// Selects all actors and propagates the action to all listeners.
        /// </summary>
        public void SelectAll()
        {
            SelectAll(null);
        }

        /// <summary>
        /// Selects all actors and propagates the action to all listeners excpet sender.
        /// </summary>
        public void SelectAll(ISelectionListener sender)
        {
            _selected.Clear();
            foreach (var actor in _all)
            {
                actor.OnSelect();
                _selected.Add(actor);
            }
            foreach (var listener in _selectionListeners)
            {
                if (sender == null || sender != listener)
                    listener.OnSelectAll();
            }
        }

        /// <summary>
        /// Deselects all actors and propagates the action to all listeners.
        /// </summary>
        public void DeselectAll()
        {
            DeselectAll(null);
        }

        /// <summary>
        /// Deselects all actors and propagates the action to all listeners excpet sender.
        /// </summary>
        public void DeselectAll(ISelectionListener sender)
        {
            foreach (var actor in _all)
                actor.OnDeselect();
            _selected.Clear();
            foreach (var listener in _selectionListeners)
            {
                if (sender == null || sender != listener)
                    listener.OnDeselectAll();
            }
        }
        
        #endregion


        #region Dragging

        /// <summary>
        /// Begins dragging all the selected actors.
        /// </summary>
        public void BeginDrag(MouseButtonEventArgs e)
        {
            foreach (var actor in _selected)
                actor.OnBeginDrag(e);
        }

        /// <summary>
        /// Drags all selected actors to the given point.
        /// </summary>
        public void Drag(MouseEventArgs e)
        {
            foreach (var actor in _selected)
                actor.OnDrag(e);
        }

        /// <summary>
        /// Tells all the selected actors to stop dragging.
        /// </summary>
        public void EndDrag(MouseButtonEventArgs e)
        {
            foreach (var actor in _selected)
                actor.OnEndDrag(e);
        }

        #endregion


    }
}
